Date: Thu Feb 27 22:59:42 2020
Scientist: Ran Yin
Sequencing (Waksman): Dibyendu Kumar (?)
Statistics: Davit Sargsyan
Principal Investigator: Ah-Ng Kong
Sources
Data
FastQ files were downloaded from this Rutgers Box location. A total of 144 files (2 per sample, pair-ended) and a pair of undetermined reads were downloaded.
16s metadata Sep-2019.xlsx meta-data file was created by Ran. It was saved as .CSV file and used by this script.
Load libraries
Questions
- Did microbiome change over time?
- Was microbiome affected by diet?
- Was microbiome affected by KO compared to WT?
FastQ files
# Get FastQ file names----
list.files(path = path,
pattern = ".gz")
[1] "RH01_S1_L001_R1_001.fastq.gz" "RH01_S1_L001_R2_001.fastq.gz" "RH02_S2_L001_R1_001.fastq.gz"
[4] "RH02_S2_L001_R2_001.fastq.gz" "RH03_S3_L001_R1_001.fastq.gz" "RH03_S3_L001_R2_001.fastq.gz"
[7] "RH04_S4_L001_R1_001.fastq.gz" "RH04_S4_L001_R2_001.fastq.gz" "RH05_S5_L001_R1_001.fastq.gz"
[10] "RH05_S5_L001_R2_001.fastq.gz" "RH06_S6_L001_R1_001.fastq.gz" "RH06_S6_L001_R2_001.fastq.gz"
[13] "RH07_S7_L001_R1_001.fastq.gz" "RH07_S7_L001_R2_001.fastq.gz" "RH08_S8_L001_R1_001.fastq.gz"
[16] "RH08_S8_L001_R2_001.fastq.gz" "RH09_S9_L001_R1_001.fastq.gz" "RH09_S9_L001_R2_001.fastq.gz"
[19] "RH10_S10_L001_R1_001.fastq.gz" "RH10_S10_L001_R2_001.fastq.gz" "RH11_S11_L001_R1_001.fastq.gz"
[22] "RH11_S11_L001_R2_001.fastq.gz" "RH12_S12_L001_R1_001.fastq.gz" "RH12_S12_L001_R2_001.fastq.gz"
[25] "RH13_S13_L001_R1_001.fastq.gz" "RH13_S13_L001_R2_001.fastq.gz" "RH14_S14_L001_R1_001.fastq.gz"
[28] "RH14_S14_L001_R2_001.fastq.gz" "RH15_S15_L001_R1_001.fastq.gz" "RH15_S15_L001_R2_001.fastq.gz"
[31] "RH16_S16_L001_R1_001.fastq.gz" "RH16_S16_L001_R2_001.fastq.gz" "RH17_S17_L001_R1_001.fastq.gz"
[34] "RH17_S17_L001_R2_001.fastq.gz" "RH18_S18_L001_R1_001.fastq.gz" "RH18_S18_L001_R2_001.fastq.gz"
[37] "RH19_S19_L001_R1_001.fastq.gz" "RH19_S19_L001_R2_001.fastq.gz" "RH20_S20_L001_R1_001.fastq.gz"
[40] "RH20_S20_L001_R2_001.fastq.gz" "RH21_S21_L001_R1_001.fastq.gz" "RH21_S21_L001_R2_001.fastq.gz"
[43] "RH22_S22_L001_R1_001.fastq.gz" "RH22_S22_L001_R2_001.fastq.gz" "RH23_S23_L001_R1_001.fastq.gz"
[46] "RH23_S23_L001_R2_001.fastq.gz" "RH24_S24_L001_R1_001.fastq.gz" "RH24_S24_L001_R2_001.fastq.gz"
[49] "RH25_S25_L001_R1_001.fastq.gz" "RH25_S25_L001_R2_001.fastq.gz" "RH26_S26_L001_R1_001.fastq.gz"
[52] "RH26_S26_L001_R2_001.fastq.gz" "RH27_S27_L001_R1_001.fastq.gz" "RH27_S27_L001_R2_001.fastq.gz"
[55] "RH28_S28_L001_R1_001.fastq.gz" "RH28_S28_L001_R2_001.fastq.gz" "RH29_S29_L001_R1_001.fastq.gz"
[58] "RH29_S29_L001_R2_001.fastq.gz" "RH30_S30_L001_R1_001.fastq.gz" "RH30_S30_L001_R2_001.fastq.gz"
[61] "RH31_S31_L001_R1_001.fastq.gz" "RH31_S31_L001_R2_001.fastq.gz" "RH32_S32_L001_R1_001.fastq.gz"
[64] "RH32_S32_L001_R2_001.fastq.gz" "RH33_S33_L001_R1_001.fastq.gz" "RH33_S33_L001_R2_001.fastq.gz"
[67] "RH34_S34_L001_R1_001.fastq.gz" "RH34_S34_L001_R2_001.fastq.gz" "RH35_S35_L001_R1_001.fastq.gz"
[70] "RH35_S35_L001_R2_001.fastq.gz" "RH36_S36_L001_R1_001.fastq.gz" "RH36_S36_L001_R2_001.fastq.gz"
Quality of reads
In gray-scale is a heat map of the frequency of each quality score at each base position. The median quality score at each position is shown by the green line, and the quartiles of the quality score distribution by the orange lines. The red line shows the scaled proportion of reads that extend to at least that position (this is more useful for other sequencing technologies, as Illumina reads are typically all the same lenghth, hence the flat red line).
Source: DADA2 Pipeline Tutorial (1.12) NOTE: the reason the quality seems to be low at the beginning is that the program is using moving averages so there are less data points in the beginning. No trimming is needed on the left.
Forward reads
user system elapsed
290.668 22.189 313.520




































Reverse reads
user system elapsed
294.714 26.558 322.720




































Filter and trim sequences
The reads were trimmed approximately to the lenght at which the quality score median (the green line) went below 20.
The forward reads were of a very good quiality. Only last 20 bases were trimmed.
The reverse read were of lower quality and were trimmed at the length of 220 bases.
sample.names <- gsub(x = fnFs,
pattern = "fastq_jan2020/",
replacement = "")
sample.names <- sapply(strsplit(sample.names, "_"),
`[`,
1)
sample.names
[1] "RH01" "RH02" "RH03" "RH04" "RH05" "RH06" "RH07" "RH08" "RH09" "RH10" "RH11" "RH12" "RH13" "RH14" "RH15" "RH16"
[17] "RH17" "RH18" "RH19" "RH20" "RH21" "RH22" "RH23" "RH24" "RH25" "RH26" "RH27" "RH28" "RH29" "RH30" "RH31" "RH32"
[33] "RH33" "RH34" "RH35" "RH36"
filtFs <- gsub(x = fnFs,
pattern = "fastq_jan2020/",
replacement = "filtered_jan2020/")
filtRs <- gsub(x = fnRs,
pattern = "fastq_jan2020/",
replacement = "filtered_jan2020/")
out <- filterAndTrim(fwd = fnFs,
filt = filtFs,
rev = fnRs,
filt.rev = filtRs,
truncLen = c(280, 220),
# trimRight = c(20, 80),
maxN = 0,
maxEE = c(2, 2),
truncQ = 2,
rm.phix = TRUE,
compress = TRUE,
multithread = FALSE)
# NOTE: multi-tread messes up pairs of the files; using single tread instead.
save(out,
file = "data_jan2020/out.RData")
gc()
used (Mb) gc trigger (Mb) max used (Mb)
Ncells 6994016 373.6 12408701 662.7 11889647 635.0
Vcells 11990477 91.5 66625207 508.4 97695243 745.4
Reads after trimming: examples


Learn the error rates
NOTE: parameter learning is computationally intensive, so by default the learnErrors function uses only a subset of the data (the first 1M reads). If the plotted error model does not look like a good fit, try increasing the nreads parameter to see if the fit improves.
# fnFs <- sort(list.files(path,
# pattern="_R1_001.fastq",
# full.names = TRUE))
# filtFs <- gsub(x = fnFs,
# pattern = "fastq_sep2019/",
# replacement = "filtered_sep2019/")
system.time(errF <- learnErrors(filtFs,
multithread = FALSE))
154626080 total bases in 552236 reads from 2 samples will be used for learning the error rates.
user system elapsed
26845.522 442.297 27277.245
save(errF,
file = "data_jan2020/errF.RData")
# fnRs <- sort(list.files(path,
# pattern="_R2_001.fastq",
# full.names = TRUE))
# filtRs <- gsub(x = fnRs,
# pattern = "fastq_sep2019/",
# replacement = "filtered_sep2019/")
system.time(errR <- learnErrors(filtRs,
multithread = FALSE))
save(errR,
file = "data_sep2019/errR.RData")
Plot learn the error rates
Dereplicate the dataset
NOTE: for larger datasets (exceeding available RAM) process samples one-by-one. See DADA2 Workflow on Big Data.
# fnFs <- sort(list.files(path,
# pattern="_R1_001.fastq",
# full.names = TRUE))
# filtFs <- gsub(x = fnFs,
# pattern = "fastq_sep2019/",
# replacement = "filtered_sep2019/")
system.time(derepFs <- derepFastq(filtFs,
verbose = TRUE))
save(derepFs,
file = "data_sep2019/derepFs.RData")
head(derepFs)
gc()
# fnRs <- sort(list.files(path,
# pattern="_R2_001.fastq",
# full.names = TRUE))
# filtRs <- gsub(x = fnRs,
# pattern = "fastq_sep2019/",
# replacement = "filtered_sep2019/")
system.time(derepRs <- derepFastq(filtRs,
verbose = TRUE))
save(derepRs,
file = "data_sep2019/derepRs.RData")
head(derepRs)
gc()
Alignment
Notes from IGS Workshop*:
Sample Inference - inferring the sequence variants in each sample.
By default, the dada function processes each sample independently, but pooled processing is available with pool=TRUE and that may give better results for low sampling depths at the cost of increased computation time.
All samples are simultaneously loaded into memory by default. If the datasets approach or exceed available RAM, it is preferable to process samples one-by-one in a streaming fashion: see DADA2 Workflow on Big Data for an example.
# load("data_sep2019/errF.RData")
# load("data_sep2019/derepFs.RData")
system.time(dadaFs <- dada(derep = derepFs,
err = errF,
multithread = TRUE))
save(dadaFs,
file = "data_sep2019/dadaFs.RData")
# load("data_sep2019/errR.RData")
# load("data_sep2019/derepRs.RData")
system.time(dadaRs <- dada(derep = derepRs,
err = errR,
multithread = TRUE))
save(dadaRs,
file = "data_sep2019/dadaRs.RData")
Merge paired reads
Make a sequence table for chimera removal
NOTE: According to the IGS, denovo chimeras are determined based on most abundant sequencins in a given data. Usually 5-7% of sequences are chimeras. It is much higher in this dataset (60.4%). IGS recommends revisiting the removal of primers, as the ambiguous nucleotides in unremoved primers interfere with chimera identification.
Number of reads per sample throughout processing
# load("data_sep2019/out.RData")
# load("data_sep2019/dadaFs.RData")
# fnFs <- sort(list.files(path,
# pattern="_R1_001.fastq",
# full.names = TRUE))
# sample.names <- gsub(x = fnFs,
# pattern = "fastq_sep2019/",
# replacement = "")
# sample.names <- sapply(strsplit(sample.names, "_"),
# `[`,
# 1)
# sample.names
getN <- function(x) {
sum(getUniques(x))
}
track <- cbind(out,
sapply(dadaFs,
getN),
sapply(mergers,
getN),
rowSums(seqtab),
rowSums(seqtab.nochim))
colnames(track) <- c("Raw",
"Filtered",
"Denoised",
"Merged",
"Tabled",
"Non-Chimeras")
rownames(track) <- sample.names
datatable(format(track,
big.mark = ","),
options = list(pageLength = nrow(track)))
IGS suggests the number of merged sequences can potentially be increased by truncating the reads less (truncLen parameter in the filterAndTrim function), specifically, making sure that the truncated reads span the amplicon. This might not be the case here as the remaining reads are relatively long (280 bases for forward and 220 reads for reverse reads).
Save amplicon sequence variants (ASV) as a FastA file
Write out and save your results thus far:
fc <- file("data_sep2019/all_runs_dada2_ASV.fasta")
fltp <- character()
for( i in 1:ncol(seqtab)) {
fltp <- append(fltp,
paste0(">Seq_",
i))
fltp <- append(fltp,
colnames(seqtab)[i])
}
writeLines(fltp,
fc)
close(fc)
head(fltp)
rm(fltp)
gc()
Assign taxonomy
NOTE: create taxa.RData once, then comment it out and load the R data file to when reruning the code.
# taxa <- assignTaxonomy(seqs = seqtab.nochim,
# refFasta = "tax/silva_nr_v132_train_set.fa",
# multithread = mt)
# save(taxa,
# file = "data_sep2019/taxa.RData")
load("data_sep2019/taxa.RData")
print(paste("Number of unique references =",
format(nrow(taxa),
big.mark = ",")))
datatable(taxa[1:5, ],
rownames = FALSE)
# Keep only the references found in the data
taxa.tmp <- taxa[rownames(taxa) %in% colnames(seqtab.nochim), ]
print(paste("Number of references matched in the data =",
format(nrow(taxa.tmp),
big.mark = ",")))
# # Add species (do it once)
# taxa.plus <- addSpecies(taxtab = taxa.tmp,
# refFasta = "tax/silva_species_assignment_v132.fa",
# verbose = TRUE)
# save(taxa.plus,
# file = "data_may2019/taxa.plus.RData")
#
# load("data_sep2019/taxa.plus.RData")
load("data_sep2019/dt.meta.RData")
dt.otu <- otu_table(seqtab.nochim,
taxa_are_rows = FALSE)
sample_names(dt.otu) <- sample.names
print("Sample names in OTU table")
sample_names(dt.otu)
metadata <- sample_data(dt.meta)
rownames(metadata) <- metadata$SAMPLE_NAME
print("Sample names in metadata")
sample_names(metadata)
metadata@row.names <- sample_names(dt.otu)
ps_sep2019 <- phyloseq(dt.otu,
metadata,
tax_table(taxa))
sample_names(ps_sep2019)
save(ps_sep2019,
file = "data_sep2019/ps_sep2019.RData")
LS0tCnRpdGxlOiAiUmFzaWthJ3MgMTZTIHNhbXBsZXMsIEphbnVhcnkgMjAyMCBCYXRjaCIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB5ZXMKICAgIHRvY19mbG9hdDogeWVzCi0tLQpEYXRlOiBgciBkYXRlKClgICAgICAKU2NpZW50aXN0OiBbUmFuIFlpbl0obWFpbHRvOnJ5MTQ3QHNjYXJsZXRtYWlsLnJ1dGdlcnMuZWR1KSAgICAgIApTZXF1ZW5jaW5nIChXYWtzbWFuKTogW0RpYnllbmR1IEt1bWFyXShtYWlsdG86ZGtAd2Frc21hbi5ydXRnZXJzLmVkdSkgKD8pICAgICAgClN0YXRpc3RpY3M6IFtEYXZpdCBTYXJnc3lhbl0obWFpbHRvOnNhcmdkYXZpZEBnbWFpbC5jb20pICAgICAgClByaW5jaXBhbCBJbnZlc3RpZ2F0b3I6IFtBaC1OZyBLb25nXShtYWlsdG86a29uZ3RAcGhhcm1hY3kucnV0Z2Vycy5lZHUpICAgICAgCgojIFNvdXJjZXMKIyMgU2NyaXB0ClRoaXMgc2NyaXB0IHdhcyBkZXZlbG9wZWQgdXNpbmcgW0RBREEyIFBpcGVsaW5lIFR1dG9yaWFsICgxLjEyKV0oaHR0cHM6Ly9iZW5qam5lYi5naXRodWIuaW8vZGFkYTIvdHV0b3JpYWwuaHRtbCkgd2l0aCB0aXBzIGFuZCB0cmlja3MgZnJvbSB0aGUgW1VuaXZlcnNpdHkgb2YgTWFyeWxhbmQgU2hvb2wgb2YgTWVkaWNpbmUgSW5zdGl0dXRlIGZvciBHZW5vbWUgU2NpZW5jZXMgKElHUyldKGh0dHA6Ly93d3cuaWdzLnVtYXJ5bGFuZC5lZHUvKSBbTWljcm9iaW9tZSBBbmFseXNpcyBXb3Jrc2hvcCAoQXByaWwgOC0xMSwgMjAxOSldKGh0dHA6Ly93d3cuaWdzLnVtYXJ5bGFuZC5lZHUvZWR1Y2F0aW9uL3drc2hwX21ldGFnZW5vbWUucGhwKS4KICAKIyMgRGF0YSAKRmFzdFEgZmlsZXMgd2VyZSBkb3dubG9hZGVkIGZyb20gW3RoaXMgUnV0Z2VycyBCb3ggbG9jYXRpb25dKGh0dHBzOi8vcnV0Z2Vycy5hcHAuYm94LmNvbS9mb2xkZXIvOTAxNDM0NjIyOTEpLiBBIHRvdGFsIG9mIDE0NCBmaWxlcyAoMiBwZXIgc2FtcGxlLCBwYWlyLWVuZGVkKSBhbmQgYSBwYWlyIG9mIHVuZGV0ZXJtaW5lZCByZWFkcyB3ZXJlIGRvd25sb2FkZWQuICAKICAKKioqMTZzIG1ldGFkYXRhIFNlcC0yMDE5Lnhsc3gqKiogbWV0YS1kYXRhIGZpbGUgd2FzIGNyZWF0ZWQgYnkgUmFuLiBJdCB3YXMgc2F2ZWQgYXMgLkNTViBmaWxlIGFuZCB1c2VkIGJ5IHRoaXMgc2NyaXB0LiAgCiAgCiMgTG9hZCBsaWJyYXJpZXMKYGBge3Igc2V0dXAsIGluY2x1ZGUgPSBGQUxTRX0KcmVxdWlyZShrbml0cikKcmVxdWlyZShrYWJsZUV4dHJhKQoKIyAjIEluY3JlYXNlIG1lbW9yeSBzaXplIHRvIDY0IEdiCiMgaW52aXNpYmxlKHV0aWxzOjptZW1vcnkubGltaXQoNjU1MzYpKQpvcHRpb25zKHN0cmluZ3NBc0ZhY3RvcnMgPSBGQUxTRSkKIyBzdHIoa25pdHI6Om9wdHNfY2h1bmskZ2V0KCkpCiMgIyBOT1RFOiB0aGUgYmVsb3cgZG9lcyBub3Qgd29yayEKIyBrbml0cjo6b3B0c19jaHVuayRzZXQoZWNobyA9IEZBTFNFLCAKIyAgICAgICAgICAgICAgICAgICAgICAgbWVzc2FnZSA9IEZBTFNFLAojICAgICAgICAgICAgICAgICAgICAgICB3YXJuaW5nID0gRkFMU0UsCiMgICAgICAgICAgICAgICAgICAgICAgIGVycm9yID0gRkFMU0UpCgojIE9uIFdpbmRvd3Mgc2V0IG11bHRpdGhyZWFkPUZBTFNFCiMgT3RoZXJ3aXNlLCBUUlVFIG9yIG51bWJlciBvZiBjb3JlcwojIG10IDwtIDMwCm10IDwtIFRSVUUKCiMgIyBTb3VyY2U6IGh0dHBzOi8vYmVuampuZWIuZ2l0aHViLmlvL2RhZGEyL2luZGV4Lmh0bWwKIyAjIEluc3RhbGxlZCBvbiBKJkogUnN0dWRpbyBzZXJ2ZXIgIG9uIDA1LzIyLzIwMTkKIyBpZiAoIXJlcXVpcmVOYW1lc3BhY2UoIkJpb2NNYW5hZ2VyIiwgcXVpZXRseSA9IFRSVUUpKQojICAgaW5zdGFsbC5wYWNrYWdlcygiQmlvY01hbmFnZXIiKQojIEJpb2NNYW5hZ2VyOjppbnN0YWxsKHZlcnNpb24gPSAiMy44IikKIyBCaW9jTWFuYWdlcjo6aW5zdGFsbCgiZGFkYTIiLCB2ZXJzaW9uID0gIjMuOCIpCiMgQmlvY01hbmFnZXI6Omluc3RhbGwoInBoeWxvc2VxIiwgdmVyc2lvbiA9ICIzLjgiKQoKIyBGb2xsb3cgdGhlIHR1dG9yaWFsOgojIGh0dHBzOi8vYmVuampuZWIuZ2l0aHViLmlvL2RhZGEyL3R1dG9yaWFsLmh0bWwKCnJlcXVpcmUoZGF0YS50YWJsZSkKcmVxdWlyZShkYWRhMikKcmVxdWlyZShwaHlsb3NlcSkKcmVxdWlyZShnZ3Bsb3QyKQpsaWJyYXJ5KHN0cmluZ3IpCnJlcXVpcmUoRFQpCgpwYXRoIDwtICJmYXN0cV9qYW4yMDIwIgpgYGAKCiMgTWV0YS1kYXRhCmBgYHtyIG1ldGFfZGF0YX0KIyBkdC5tZXRhIDwtIGZyZWFkKCJkYXRhX2phbjIwMjAvMTZzIG1ldGFkYXRhIFNlcC0yMDE5LmNzdiIpCiMgc2F2ZShkdC5tZXRhLAojICAgICAgZmlsZSA9ICJkYXRhX3NlcDIwMTkvZHQubWV0YS5SRGF0YSIpCiMgZGF0YXRhYmxlKGR0Lm1ldGEsCiMgICAgICAgICAgIGNhcHRpb24gPSAiVGFibGUgMTogTWV0YS1EYXRhIiwKIyAgICAgICAgICAgcm93bmFtZXMgPSBGQUxTRSwKIyAgICAgICAgICAgY2xhc3MgPSAiY2VsbC1ib3JkZXIgc3RyaXBlIiwKIyAgICAgICAgICAgb3B0aW9ucyA9IGxpc3Qoc2VhcmNoaW5nID0gVFJVRSwKIyAgICAgICAgICAgICAgICAgICAgICAgICAgcGFnZUxlbmd0aCA9IDgpKQpgYGAKICAKKipOT1RFKio6IG1vdmVkICJVbmRldGVybWluZWQiIHNhbXBsZXMgZnJvbSB0aGUgRmFzdFEgZm9sZGVyIHRvIHRoZSBkb2NzIGZvbGRlci4gIAogIAojIFF1ZXN0aW9ucwoxLiBEaWQgbWljcm9iaW9tZSBjaGFuZ2Ugb3ZlciB0aW1lPyAgIAoyLiBXYXMgbWljcm9iaW9tZSBhZmZlY3RlZCBieSBkaWV0PyAgCjMuIFdhcyBtaWNyb2Jpb21lIGFmZmVjdGVkIGJ5IEtPIGNvbXBhcmVkIHRvIFdUPyAgCiAgCiMgRmFzdFEgZmlsZXMKYGBge3IgZmFzdHF9CiMgR2V0IEZhc3RRIGZpbGUgbmFtZXMtLS0tCmxpc3QuZmlsZXMocGF0aCA9IHBhdGgsCiAgICAgICAgICAgcGF0dGVybiA9ICIuZ3oiKQpgYGAKCiMgUXVhbGl0eSBvZiByZWFkcwpJbiAqKmdyYXktc2NhbGUqKiBpcyBhIGhlYXQgbWFwIG9mIHRoZSBmcmVxdWVuY3kgb2YgZWFjaCBxdWFsaXR5IHNjb3JlIGF0IGVhY2ggYmFzZSBwb3NpdGlvbi4gVGhlIG1lZGlhbiBxdWFsaXR5IHNjb3JlIGF0IGVhY2ggcG9zaXRpb24gaXMgc2hvd24gYnkgdGhlICoqZ3JlZW4qKiBsaW5lLCBhbmQgdGhlIHF1YXJ0aWxlcyBvZiB0aGUgcXVhbGl0eSBzY29yZSBkaXN0cmlidXRpb24gYnkgdGhlICoqb3JhbmdlKiogbGluZXMuIFRoZSAqKnJlZCoqIGxpbmUgc2hvd3MgdGhlIHNjYWxlZCBwcm9wb3J0aW9uIG9mIHJlYWRzIHRoYXQgZXh0ZW5kIHRvIGF0IGxlYXN0IHRoYXQgcG9zaXRpb24gKHRoaXMgaXMgbW9yZSB1c2VmdWwgZm9yIG90aGVyIHNlcXVlbmNpbmcgdGVjaG5vbG9naWVzLCBhcyBJbGx1bWluYSByZWFkcyBhcmUgdHlwaWNhbGx5IGFsbCB0aGUgc2FtZSBsZW5naHRoLCBoZW5jZSB0aGUgZmxhdCByZWQgbGluZSkuICAgICAgClNvdXJjZTogW0RBREEyIFBpcGVsaW5lIFR1dG9yaWFsICgxLjEyKV0oaHR0cHM6Ly9iZW5qam5lYi5naXRodWIuaW8vZGFkYTIvdHV0b3JpYWwuaHRtbCkgCioqTk9URSoqOiB0aGUgcmVhc29uIHRoZSBxdWFsaXR5IHNlZW1zIHRvIGJlIGxvdyBhdCB0aGUgYmVnaW5uaW5nIGlzIHRoYXQgdGhlIHByb2dyYW0gaXMgdXNpbmcgbW92aW5nIGF2ZXJhZ2VzIHNvIHRoZXJlIGFyZSBsZXNzIGRhdGEgcG9pbnRzIGluIHRoZSBiZWdpbm5pbmcuIE5vIHRyaW1taW5nIGlzIG5lZWRlZCBvbiB0aGUgbGVmdC4KCiMjIEZvcndhcmQgcmVhZHMKYGBge3IgcGxvdF9xdWFsaXR5X2Z3ZCwgd2FybmluZ3MgPSBGQUxTRSwgZWNobyA9IEZBTFNFLCBtZXNzYWdlID0gRkFMU0UsIGZpZy5oZWlnaHQgPSA0LCBmaWcud2lkdGggPSA1fQpmbkZzIDwtIHNvcnQobGlzdC5maWxlcyhwYXRoLCAKICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybj0iX1IxXzAwMS5mYXN0cSIsIAogICAgICAgICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkpCnN5c3RlbS50aW1lKHsKICBmb3IgKGkgaW4gMTpsZW5ndGgoZm5GcykpIHsKICAgIHByaW50KHBsb3RRdWFsaXR5UHJvZmlsZShmbkZzW2ldKSkKICB9Cn0pCmBgYAoKIyMgUmV2ZXJzZSByZWFkcwpgYGB7ciBwbG90X3F1YWxpdHlfcmV2LCB3YXJuaW5ncyA9IEZBTFNFLCBlY2hvID0gRkFMU0UsIG1lc3NhZ2UgPSBGQUxTRSwgZmlnLmhlaWdodCA9IDQsIGZpZy53aWR0aCA9IDV9CmZuUnMgPC0gc29ydChsaXN0LmZpbGVzKHBhdGgsCiAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm49Il9SMl8wMDEuZmFzdHEiLAogICAgICAgICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkpCnN5c3RlbS50aW1lKHsKICBmb3IgKGkgaW4gMTpsZW5ndGgoZm5ScykpIHsKICAgIHByaW50KHBsb3RRdWFsaXR5UHJvZmlsZShmblJzW2ldKSkKICB9Cn0pCmBgYAoKIyBGaWx0ZXIgYW5kIHRyaW0gc2VxdWVuY2VzClRoZSByZWFkcyB3ZXJlIHRyaW1tZWQgYXBwcm94aW1hdGVseSB0byB0aGUgbGVuZ2h0IGF0IHdoaWNoIHRoZSBxdWFsaXR5IHNjb3JlIG1lZGlhbiAodGhlICoqZ3JlZW4qKiBsaW5lKSB3ZW50IGJlbG93IDIwLiAgICAKVGhlIGZvcndhcmQgcmVhZHMgd2VyZSBvZiBhIHZlcnkgZ29vZCBxdWlhbGl0eS4gT25seSBsYXN0IDIwIGJhc2VzIHdlcmUgdHJpbW1lZC4gICAgClRoZSByZXZlcnNlIHJlYWQgd2VyZSBvZiBsb3dlciBxdWFsaXR5IGFuZCB3ZXJlIHRyaW1tZWQgYXQgdGhlIGxlbmd0aCBvZiAyMjAgYmFzZXMuICAKICAKYGBge3Igc29ydF9uX3RyaW1fcHJlcH0Kc2FtcGxlLm5hbWVzIDwtIGdzdWIoeCA9IGZuRnMsCiAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiZmFzdHFfamFuMjAyMC8iLAogICAgICAgICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICIiKQpzYW1wbGUubmFtZXMgPC0gc2FwcGx5KHN0cnNwbGl0KHNhbXBsZS5uYW1lcywgIl8iKSwKICAgICAgICAgICAgICAgICAgICAgICBgW2AsIAogICAgICAgICAgICAgICAgICAgICAgIDEpCnNhbXBsZS5uYW1lcwoKZmlsdEZzIDwtIGdzdWIoeCA9IGZuRnMsCiAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiZmFzdHFfamFuMjAyMC8iLAogICAgICAgICAgICAgICByZXBsYWNlbWVudCA9ICJmaWx0ZXJlZF9qYW4yMDIwLyIpCgpmaWx0UnMgPC0gZ3N1Yih4ID0gZm5ScywKICAgICAgICAgICAgICAgcGF0dGVybiA9ICJmYXN0cV9qYW4yMDIwLyIsCiAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gImZpbHRlcmVkX2phbjIwMjAvIikKYGBgCgpgYGB7ciBzb3J0X25fdHJpbX0Kb3V0IDwtIGZpbHRlckFuZFRyaW0oZndkID0gZm5GcywgCiAgICAgICAgICAgICAgICAgICAgIGZpbHQgPSBmaWx0RnMsCiAgICAgICAgICAgICAgICAgICAgIHJldiA9IGZuUnMsIAogICAgICAgICAgICAgICAgICAgICBmaWx0LnJldiA9IGZpbHRScywgCiAgICAgICAgICAgICAgICAgICAgIHRydW5jTGVuID0gYygyODAsIDIyMCksCiAgICAgICAgICAgICAgICAgICAgICMgdHJpbVJpZ2h0ID0gYygyMCwgODApLAogICAgICAgICAgICAgICAgICAgICBtYXhOID0gMCwgCiAgICAgICAgICAgICAgICAgICAgIG1heEVFID0gYygyLCAyKSwgCiAgICAgICAgICAgICAgICAgICAgIHRydW5jUSA9IDIsIAogICAgICAgICAgICAgICAgICAgICBybS5waGl4ID0gVFJVRSwgCiAgICAgICAgICAgICAgICAgICAgIGNvbXByZXNzID0gVFJVRSwKICAgICAgICAgICAgICAgICAgICAgbXVsdGl0aHJlYWQgPSBGQUxTRSkKIyBOT1RFOiBtdWx0aS10cmVhZCBtZXNzZXMgdXAgcGFpcnMgb2YgdGhlIGZpbGVzOyB1c2luZyBzaW5nbGUgdHJlYWQgaW5zdGVhZC4KCnNhdmUob3V0LAogICAgIGZpbGUgPSAiZGF0YV9qYW4yMDIwL291dC5SRGF0YSIpCmdjKCkKYGBgCgojIFJlYWRzIGFmdGVyIHRyaW1taW5nOiBleGFtcGxlcwpgYGB7ciB0cmltX3Jldix3YXJuaW5ncz1GQUxTRSxlY2hvPUZBTFNFLG1lc3NhZ2U9RkFMU0V9CnBsb3RRdWFsaXR5UHJvZmlsZShmaWx0RnNbMV0pCnBsb3RRdWFsaXR5UHJvZmlsZShmaWx0UnNbMV0pCmBgYAoKIyBMZWFybiB0aGUgZXJyb3IgcmF0ZXMKKipOT1RFKio6IHBhcmFtZXRlciBsZWFybmluZyBpcyBjb21wdXRhdGlvbmFsbHkgaW50ZW5zaXZlLCBzbyBieSBkZWZhdWx0IHRoZSBsZWFybkVycm9ycyBmdW5jdGlvbiB1c2VzIG9ubHkgYSBzdWJzZXQgb2YgdGhlIGRhdGEgKHRoZSBmaXJzdCAxTSByZWFkcykuIElmIHRoZSBwbG90dGVkIGVycm9yIG1vZGVsIGRvZXMgbm90IGxvb2sgbGlrZSBhIGdvb2QgZml0LCB0cnkgaW5jcmVhc2luZyB0aGUgbnJlYWRzIHBhcmFtZXRlciB0byBzZWUgaWYgdGhlIGZpdCBpbXByb3Zlcy4KYGBge3IgbGVhcm5fZXJyb3JfZnN9CiMgZm5GcyA8LSBzb3J0KGxpc3QuZmlsZXMocGF0aCwKIyAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuPSJfUjFfMDAxLmZhc3RxIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkpCiMgZmlsdEZzIDwtIGdzdWIoeCA9IGZuRnMsCiMgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJmYXN0cV9zZXAyMDE5LyIsCiMgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiZmlsdGVyZWRfc2VwMjAxOS8iKQoKc3lzdGVtLnRpbWUoZXJyRiA8LSBsZWFybkVycm9ycyhmaWx0RnMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11bHRpdGhyZWFkID0gRkFMU0UpKQpzYXZlKGVyckYsCiAgICAgZmlsZSA9ICJkYXRhX2phbjIwMjAvZXJyRi5SRGF0YSIpCmBgYAoKYGBge3IgbGVhcm5fZXJyb3JfcnN9CiMgZm5ScyA8LSBzb3J0KGxpc3QuZmlsZXMocGF0aCwKIyAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuPSJfUjJfMDAxLmZhc3RxIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkpCiMgZmlsdFJzIDwtIGdzdWIoeCA9IGZuUnMsCiMgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJmYXN0cV9zZXAyMDE5LyIsCiMgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiZmlsdGVyZWRfc2VwMjAxOS8iKQoKc3lzdGVtLnRpbWUoZXJyUiA8LSBsZWFybkVycm9ycyhmaWx0UnMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIG11bHRpdGhyZWFkID0gRkFMU0UpKQpzYXZlKGVyclIsCiAgICAgZmlsZSA9ICJkYXRhX3NlcDIwMTkvZXJyUi5SRGF0YSIpCmBgYAoKIyBQbG90IGxlYXJuIHRoZSBlcnJvciByYXRlcwpgYGB7ciBwbG90X2Vycm9yLHdhcm5pbmdzPUZBTFNFLGVjaG89RkFMU0UsbWVzc2FnZT1GQUxTRX0KcGxvdEVycm9ycyhlcnJGLCAKICAgICAgICAgICBub21pbmFsUSA9IFRSVUUpCnBsb3RFcnJvcnMoZXJyUiwgCiAgICAgICAgICAgbm9taW5hbFEgPSBUUlVFKQpgYGAKCiMgRGVyZXBsaWNhdGUgdGhlIGRhdGFzZXQgCioqTk9URSoqOiBmb3IgbGFyZ2VyIGRhdGFzZXRzIChleGNlZWRpbmcgYXZhaWxhYmxlIFJBTSkgcHJvY2VzcyBzYW1wbGVzIG9uZS1ieS1vbmUuIFNlZSBbREFEQTIgV29ya2Zsb3cgb24gQmlnIERhdGFdKGh0dHBzOi8vYmVuampuZWIuZ2l0aHViLmlvL2RhZGEyL2JpZ2RhdGEuaHRtbCkuCmBgYHtyIGRlcmVwbGljYXRlX2ZzfQojIGZuRnMgPC0gc29ydChsaXN0LmZpbGVzKHBhdGgsIAojICAgICAgICAgICAgICAgICAgICAgICAgIHBhdHRlcm49Il9SMV8wMDEuZmFzdHEiLCAKIyAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkpCiMgZmlsdEZzIDwtIGdzdWIoeCA9IGZuRnMsCiMgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJmYXN0cV9zZXAyMDE5LyIsCiMgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiZmlsdGVyZWRfc2VwMjAxOS8iKQoKc3lzdGVtLnRpbWUoZGVyZXBGcyA8LSBkZXJlcEZhc3RxKGZpbHRGcywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gVFJVRSkpCnNhdmUoZGVyZXBGcywKICAgICBmaWxlID0gImRhdGFfc2VwMjAxOS9kZXJlcEZzLlJEYXRhIikKCmhlYWQoZGVyZXBGcykKZ2MoKQpgYGAKCmBgYHtyIGRlcmVwbGljYXRlX3JzfQojIGZuUnMgPC0gc29ydChsaXN0LmZpbGVzKHBhdGgsCiMgICAgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybj0iX1IyXzAwMS5mYXN0cSIsCiMgICAgICAgICAgICAgICAgICAgICAgICAgZnVsbC5uYW1lcyA9IFRSVUUpKQojIGZpbHRScyA8LSBnc3ViKHggPSBmblJzLAojICAgICAgICAgICAgICAgIHBhdHRlcm4gPSAiZmFzdHFfc2VwMjAxOS8iLAojICAgICAgICAgICAgICAgIHJlcGxhY2VtZW50ID0gImZpbHRlcmVkX3NlcDIwMTkvIikKCnN5c3RlbS50aW1lKGRlcmVwUnMgPC0gZGVyZXBGYXN0cShmaWx0UnMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IFRSVUUpKQpzYXZlKGRlcmVwUnMsCiAgICAgZmlsZSA9ICJkYXRhX3NlcDIwMTkvZGVyZXBScy5SRGF0YSIpCgpoZWFkKGRlcmVwUnMpCmdjKCkKYGBgCgojIEFsaWdubWVudAoqKk5vdGVzIGZyb20gSUdTIFdvcmtzaG9wKioqOiAgICAKU2FtcGxlIEluZmVyZW5jZSAtIGluZmVycmluZyB0aGUgc2VxdWVuY2UgdmFyaWFudHMgaW4gZWFjaCBzYW1wbGUuICAgICAKICAgICAgCkJ5IGRlZmF1bHQsIHRoZSAqKipkYWRhKioqIGZ1bmN0aW9uIHByb2Nlc3NlcyBlYWNoIHNhbXBsZSBpbmRlcGVuZGVudGx5LCBidXQgcG9vbGVkIHByb2Nlc3NpbmcgaXMgYXZhaWxhYmxlIHdpdGggKioqcG9vbD1UUlVFKioqIGFuZCB0aGF0IG1heSBnaXZlIGJldHRlciByZXN1bHRzIGZvciBsb3cgc2FtcGxpbmcgZGVwdGhzIGF0IHRoZSBjb3N0IG9mIGluY3JlYXNlZCBjb21wdXRhdGlvbiB0aW1lLiAgICAgCiAgICAgCkFsbCBzYW1wbGVzIGFyZSBzaW11bHRhbmVvdXNseSBsb2FkZWQgaW50byBtZW1vcnkgYnkgZGVmYXVsdC4gSWYgdGhlIGRhdGFzZXRzIGFwcHJvYWNoIG9yIGV4Y2VlZCBhdmFpbGFibGUgUkFNLCBpdCBpcyBwcmVmZXJhYmxlIHRvIHByb2Nlc3Mgc2FtcGxlcyBvbmUtYnktb25lIGluIGEgc3RyZWFtaW5nIGZhc2hpb246IHNlZSBbREFEQTIgV29ya2Zsb3cgb24gQmlnIERhdGFdKGh0dHBzOi8vYmVuampuZWIuZ2l0aHViLmlvL2RhZGEyL2JpZ2RhdGEuaHRtbCkgZm9yIGFuIGV4YW1wbGUuICAgIApgYGB7ciBkYWRhX2ZzfQojIGxvYWQoImRhdGFfc2VwMjAxOS9lcnJGLlJEYXRhIikKIyBsb2FkKCJkYXRhX3NlcDIwMTkvZGVyZXBGcy5SRGF0YSIpCgpzeXN0ZW0udGltZShkYWRhRnMgPC0gZGFkYShkZXJlcCA9IGRlcmVwRnMsIAogICAgICAgICAgICAgICAgICAgICAgICAgICBlcnIgPSBlcnJGLAogICAgICAgICAgICAgICAgICAgICAgICAgICBtdWx0aXRocmVhZCA9IFRSVUUpKQpzYXZlKGRhZGFGcywKICAgICBmaWxlID0gImRhdGFfc2VwMjAxOS9kYWRhRnMuUkRhdGEiKQpgYGAKCmBgYHtyIGRhZGFfcnN9CiMgbG9hZCgiZGF0YV9zZXAyMDE5L2VyclIuUkRhdGEiKQojIGxvYWQoImRhdGFfc2VwMjAxOS9kZXJlcFJzLlJEYXRhIikKCnN5c3RlbS50aW1lKGRhZGFScyA8LSBkYWRhKGRlcmVwID0gZGVyZXBScywgCiAgICAgICAgICAgICAgICAgICAgICAgICAgIGVyciA9IGVyclIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgIG11bHRpdGhyZWFkID0gVFJVRSkpCnNhdmUoZGFkYVJzLAogICAgIGZpbGUgPSAiZGF0YV9zZXAyMDE5L2RhZGFScy5SRGF0YSIpCmBgYAoKIyBNZXJnZSBwYWlyZWQgcmVhZHMKYGBge3IgbWVyZ2Usd2FybmluZ3M9RkFMU0UsZWNobz1GQUxTRSxtZXNzYWdlPUZBTFNFLGV2YWw9VFJVRX0KIyBsb2FkKCJkYXRhX3NlcDIwMTkvZGFkYUZzLlJEYXRhIikKIyBsb2FkKCJkYXRhX3NlcDIwMTkvZGVyZXBGcy5SRGF0YSIpCiMgbG9hZCgiZGF0YV9zZXAyMDE5L2RhZGFScy5SRGF0YSIpCiMgbG9hZCgiZGF0YV9zZXAyMDE5L2RlcmVwUnMuUkRhdGEiKQoKc3lzdGVtLnRpbWUobWVyZ2VycyA8LSBtZXJnZVBhaXJzKGRhZGFGID0gZGFkYUZzLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGVyZXBGID0gZGVyZXBGcywKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRhZGFSID0gZGFkYVJzLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRlcmVwUiA9IGRlcmVwUnMsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gVFJVRSkpCnNhdmUobWVyZ2VycywKICAgICBmaWxlID0gImRhdGFfc2VwMjAxOS9tZXJnZXJzLlJEYXRhIikKYGBgCgojIE1ha2UgYSBzZXF1ZW5jZSB0YWJsZSBmb3IgY2hpbWVyYSByZW1vdmFsCmBgYHtyIGNoaW1lcmEsd2FybmluZ3M9RkFMU0UsZWNobz1GQUxTRSxtZXNzYWdlPUZBTFNFLGV2YWw9VFJVRX0KIyBsb2FkKCJkYXRhX3NlcDIwMTkvbWVyZ2Vycy5SRGF0YSIpCgpzeXN0ZW0udGltZShzZXF0YWIgPC0gbWFrZVNlcXVlbmNlVGFibGUobWVyZ2VycykpCgpkaW0oc2VxdGFiKQpzYXZlKHNlcXRhYiwKICAgICBmaWxlID0gImRhdGFfc2VwMjAxOS9zZXF0YWIuUkRhdGEiKQpnYygpCgojIFJlbW92ZSBjaGltZXJhcwpzeXN0ZW0udGltZShzZXF0YWIubm9jaGltIDwtIHJlbW92ZUJpbWVyYURlbm92byh1bnFzID0gc2VxdGFiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAiY29uc2Vuc3VzIiwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgbXVsdGl0aHJlYWQgPSBtdCwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgdmVyYm9zZSA9IFRSVUUpKQoKZGltKHNlcXRhYi5ub2NoaW0pIApzYXZlKHNlcXRhYi5ub2NoaW0sCiAgICAgZmlsZSA9ICJkYXRhX21heTIwMTkvc2VxdGFiLm5vY2hpbS5SRGF0YSIpCndyaXRlLmNzdihzZXF0YWIubm9jaGltLCAKICAgICAgICAgIGZpbGUgPSAiZGF0YV9tYXkyMDE5L3NlcXRhYi5ub2NoaW0uY3N2IiwgCiAgICAgICAgICBxdW90ZSA9IEZBTFNFKQoKIyAxIC0gcHJvcG9ydGlvbiBvZiBjaGltZXJhcwpwcmludChwYXN0ZSgiQ2hpbWVyYXMgPSAiLAogICAgICAgICAgICByb3VuZCgxMDAqKDEgLSAoc3VtKHNlcXRhYi5ub2NoaW0pL3N1bShzZXF0YWIpKSksIDEpLAogICAgICAgICAgICAiJSIsCiAgICAgICAgICAgIHNlcCA9ICIiKSkKYGBgCgoqKk5PVEUqKjogQWNjb3JkaW5nIHRvIHRoZSBJR1MsIGRlbm92byBjaGltZXJhcyBhcmUgZGV0ZXJtaW5lZCBiYXNlZCBvbiBtb3N0IGFidW5kYW50IHNlcXVlbmNpbnMgaW4gYSBnaXZlbiBkYXRhLiBVc3VhbGx5IDUtNyUgb2Ygc2VxdWVuY2VzIGFyZSBjaGltZXJhcy4gSXQgaXMgbXVjaCBoaWdoZXIgaW4gdGhpcyBkYXRhc2V0ICg2MC40JSkuIElHUyByZWNvbW1lbmRzIHJldmlzaXRpbmcgdGhlIHJlbW92YWwgb2YgcHJpbWVycywgYXMgdGhlIGFtYmlndW91cyBudWNsZW90aWRlcyBpbiB1bnJlbW92ZWQgcHJpbWVycyBpbnRlcmZlcmUgd2l0aCBjaGltZXJhIGlkZW50aWZpY2F0aW9uLiAKCiMjIE51bWJlciBvZiByZWFkcyBwZXIgc2FtcGxlIHRocm91Z2hvdXQgcHJvY2Vzc2luZwpgYGB7ciBjaGVja19sZW5ndGh9CiMgbG9hZCgiZGF0YV9zZXAyMDE5L291dC5SRGF0YSIpCiMgbG9hZCgiZGF0YV9zZXAyMDE5L2RhZGFGcy5SRGF0YSIpCiMgZm5GcyA8LSBzb3J0KGxpc3QuZmlsZXMocGF0aCwKIyAgICAgICAgICAgICAgICAgICAgICAgICBwYXR0ZXJuPSJfUjFfMDAxLmZhc3RxIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICBmdWxsLm5hbWVzID0gVFJVRSkpCiMgc2FtcGxlLm5hbWVzIDwtIGdzdWIoeCA9IGZuRnMsCiMgICAgICAgICAgICAgICAgICAgICAgcGF0dGVybiA9ICJmYXN0cV9zZXAyMDE5LyIsCiMgICAgICAgICAgICAgICAgICAgICAgcmVwbGFjZW1lbnQgPSAiIikKIyBzYW1wbGUubmFtZXMgPC0gc2FwcGx5KHN0cnNwbGl0KHNhbXBsZS5uYW1lcywgIl8iKSwKIyAgICAgICAgICAgICAgICAgICAgICAgIGBbYCwgCiMgICAgICAgICAgICAgICAgICAgICAgICAxKQojIHNhbXBsZS5uYW1lcwoKZ2V0TiA8LSBmdW5jdGlvbih4KSB7CiAgc3VtKGdldFVuaXF1ZXMoeCkpCn0gCnRyYWNrIDwtIGNiaW5kKG91dCwgCiAgICAgICAgICAgICAgIHNhcHBseShkYWRhRnMsIAogICAgICAgICAgICAgICAgICAgICAgZ2V0TiksCiAgICAgICAgICAgICAgIHNhcHBseShtZXJnZXJzLAogICAgICAgICAgICAgICAgICAgICAgZ2V0TiksCiAgICAgICAgICAgICAgIHJvd1N1bXMoc2VxdGFiKSwgCiAgICAgICAgICAgICAgIHJvd1N1bXMoc2VxdGFiLm5vY2hpbSkpCmNvbG5hbWVzKHRyYWNrKSA8LSBjKCJSYXciLCAKICAgICAgICAgICAgICAgICAgICAgIkZpbHRlcmVkIiwKICAgICAgICAgICAgICAgICAgICAgIkRlbm9pc2VkIiwgCiAgICAgICAgICAgICAgICAgICAgICJNZXJnZWQiLAogICAgICAgICAgICAgICAgICAgICAiVGFibGVkIiwKICAgICAgICAgICAgICAgICAgICAgIk5vbi1DaGltZXJhcyIpCnJvd25hbWVzKHRyYWNrKSA8LSBzYW1wbGUubmFtZXMKZGF0YXRhYmxlKGZvcm1hdCh0cmFjaywKICAgICAgICAgICAgICAgICBiaWcubWFyayA9ICIsIiksCiAgICAgICAgICBvcHRpb25zID0gbGlzdChwYWdlTGVuZ3RoID0gbnJvdyh0cmFjaykpKQpgYGAKCklHUyBzdWdnZXN0cyB0aGUgbnVtYmVyIG9mICoqbWVyZ2VkKiogc2VxdWVuY2VzIGNhbiBwb3RlbnRpYWxseSBiZSBpbmNyZWFzZWQgYnkgdHJ1bmNhdGluZyB0aGUgcmVhZHMgbGVzcyAoKioqdHJ1bmNMZW4qKiogcGFyYW1ldGVyIGluIHRoZSAqKipmaWx0ZXJBbmRUcmltKioqIGZ1bmN0aW9uKSwgc3BlY2lmaWNhbGx5LCBtYWtpbmcgc3VyZSB0aGF0IHRoZSB0cnVuY2F0ZWQgcmVhZHMgc3BhbiB0aGUgYW1wbGljb24uIFRoaXMgbWlnaHQgbm90IGJlIHRoZSBjYXNlIGhlcmUgYXMgdGhlIHJlbWFpbmluZyByZWFkcyBhcmUgcmVsYXRpdmVseSBsb25nICgyODAgYmFzZXMgZm9yIGZvcndhcmQgYW5kIDIyMCByZWFkcyBmb3IgcmV2ZXJzZSByZWFkcykuCgojIFNhdmUgYW1wbGljb24gc2VxdWVuY2UgdmFyaWFudHMgKEFTVikgYXMgYSBGYXN0QSBmaWxlCldyaXRlIG91dCBhbmQgc2F2ZSB5b3VyIHJlc3VsdHMgdGh1cyBmYXI6IApgYGB7ciBzYXZlX2Zhc3RhX2Fzdn0KZmMgPC0gZmlsZSgiZGF0YV9zZXAyMDE5L2FsbF9ydW5zX2RhZGEyX0FTVi5mYXN0YSIpCmZsdHAgPC0gY2hhcmFjdGVyKCkKZm9yKCBpIGluIDE6bmNvbChzZXF0YWIpKSB7CiAgZmx0cCA8LSBhcHBlbmQoZmx0cCwgCiAgICAgICAgICAgICAgICAgcGFzdGUwKCI+U2VxXyIsIAogICAgICAgICAgICAgICAgICAgICAgICBpKSkKICBmbHRwIDwtIGFwcGVuZChmbHRwLAogICAgICAgICAgICAgICAgIGNvbG5hbWVzKHNlcXRhYilbaV0pCn0Kd3JpdGVMaW5lcyhmbHRwLCAKICAgICAgICAgICBmYykKY2xvc2UoZmMpCmhlYWQoZmx0cCkKcm0oZmx0cCkKZ2MoKQpgYGAKCiMgQXNzaWduIHRheG9ub215CioqTk9URSoqOiBjcmVhdGUgKioqdGF4YS5SRGF0YSoqKiBvbmNlLCB0aGVuIGNvbW1lbnQgaXQgb3V0IGFuZCBsb2FkIHRoZSBSIGRhdGEgZmlsZSB0byB3aGVuIHJlcnVuaW5nIHRoZSBjb2RlLiAKYGBge3IgdGF4X2Fzc2lnbn0KIyB0YXhhIDwtIGFzc2lnblRheG9ub215KHNlcXMgPSBzZXF0YWIubm9jaGltLAojICAgICAgICAgICAgICAgICAgICAgICAgcmVmRmFzdGEgPSAidGF4L3NpbHZhX25yX3YxMzJfdHJhaW5fc2V0LmZhIiwKIyAgICAgICAgICAgICAgICAgICAgICAgIG11bHRpdGhyZWFkID0gbXQpCiMgc2F2ZSh0YXhhLAojICAgICAgZmlsZSA9ICJkYXRhX3NlcDIwMTkvdGF4YS5SRGF0YSIpCgpsb2FkKCJkYXRhX3NlcDIwMTkvdGF4YS5SRGF0YSIpCnByaW50KHBhc3RlKCJOdW1iZXIgb2YgdW5pcXVlIHJlZmVyZW5jZXMgPSIsCiAgICAgICAgICAgIGZvcm1hdChucm93KHRheGEpLAogICAgICAgICAgICAgICAgICAgYmlnLm1hcmsgPSAiLCIpKSkKCmRhdGF0YWJsZSh0YXhhWzE6NSwgXSwKICAgICAgICAgIHJvd25hbWVzID0gRkFMU0UpCgojIEtlZXAgb25seSB0aGUgcmVmZXJlbmNlcyBmb3VuZCBpbiB0aGUgZGF0YQp0YXhhLnRtcCA8LSB0YXhhW3Jvd25hbWVzKHRheGEpICVpbiUgY29sbmFtZXMoc2VxdGFiLm5vY2hpbSksIF0KcHJpbnQocGFzdGUoIk51bWJlciBvZiByZWZlcmVuY2VzIG1hdGNoZWQgaW4gdGhlIGRhdGEgPSIsCiAgICAgICAgICAgIGZvcm1hdChucm93KHRheGEudG1wKSwKICAgICAgICAgICAgICAgICAgIGJpZy5tYXJrID0gIiwiKSkpCgojICMgQWRkIHNwZWNpZXMgKGRvIGl0IG9uY2UpCiMgdGF4YS5wbHVzIDwtIGFkZFNwZWNpZXModGF4dGFiID0gdGF4YS50bXAsCiMgICAgICAgICAgICAgICAgICAgICAgICAgcmVmRmFzdGEgPSAidGF4L3NpbHZhX3NwZWNpZXNfYXNzaWdubWVudF92MTMyLmZhIiwKIyAgICAgICAgICAgICAgICAgICAgICAgICB2ZXJib3NlID0gVFJVRSkKIyBzYXZlKHRheGEucGx1cywKIyAgICAgIGZpbGUgPSAiZGF0YV9tYXkyMDE5L3RheGEucGx1cy5SRGF0YSIpCiMgCiMgbG9hZCgiZGF0YV9zZXAyMDE5L3RheGEucGx1cy5SRGF0YSIpCmBgYAoKYGBge3IgcGh5bG9zZXF9CmxvYWQoImRhdGFfc2VwMjAxOS9kdC5tZXRhLlJEYXRhIikKZHQub3R1IDwtIG90dV90YWJsZShzZXF0YWIubm9jaGltLCAKICAgICAgICAgICAgICAgICAgICB0YXhhX2FyZV9yb3dzID0gRkFMU0UpCnNhbXBsZV9uYW1lcyhkdC5vdHUpIDwtIHNhbXBsZS5uYW1lcwpwcmludCgiU2FtcGxlIG5hbWVzIGluIE9UVSB0YWJsZSIpCnNhbXBsZV9uYW1lcyhkdC5vdHUpCgptZXRhZGF0YSA8LSBzYW1wbGVfZGF0YShkdC5tZXRhKQpyb3duYW1lcyhtZXRhZGF0YSkgPC0gbWV0YWRhdGEkU0FNUExFX05BTUUKcHJpbnQoIlNhbXBsZSBuYW1lcyBpbiBtZXRhZGF0YSIpCnNhbXBsZV9uYW1lcyhtZXRhZGF0YSkKCm1ldGFkYXRhQHJvdy5uYW1lcyA8LSBzYW1wbGVfbmFtZXMoZHQub3R1KQoKcHNfc2VwMjAxOSA8LSBwaHlsb3NlcShkdC5vdHUsIAogICAgICAgICAgICAgICAgICAgICAgIG1ldGFkYXRhLAogICAgICAgICAgICAgICAgICAgICAgIHRheF90YWJsZSh0YXhhKSkKc2FtcGxlX25hbWVzKHBzX3NlcDIwMTkpCnNhdmUocHNfc2VwMjAxOSwKICAgICBmaWxlID0gImRhdGFfc2VwMjAxOS9wc19zZXAyMDE5LlJEYXRhIikKYGBgCgojIFNlc3Npb24gSW5mb3JtYXRpb24KYGBge3IgaW5mbyxldmFsPVRSVUV9CnNlc3Npb25JbmZvKCkKYGBg